# coding: utf-8
# @Author: ChuiZi
import json
import os
import re

from lib.common.manageFile import deleteAllFile
from options.configs import FrameDataPath
from lib.frameTool.achieveTestDatas import LoadTestDatas
from settings import reportFormat, commonParams, params, caseCount


# 根据测试用例数据创建测试用例执行代码
class CreateTestCase:
    def __init__(self):
        with open(FrameDataPath.pathTestCaseTemplate, "r", encoding="utf-8") as f1:
            self.templateCase = f1.read()
        self.reportTypes = ["html", "allure"]
        self.caseCountCommon = 0
        self.caseCountHasParams = 0

    def run(self, report_typeID: int = reportFormat):
        """
        思路:遍历所有功能点之前,先把走获取通用参数的功能点,将这些功能点的order从1开始,普通前置参数从1000开始,相当于留了1000个通用参数,其他普通用例直接设置为None
        :param report_typeID:
        :return:
        """
        deleteAllFile(FrameDataPath.pathTestCaseDir, True)
        test_case_data = LoadTestDatas().run()  # 载入用例数据
        with open(os.path.join(FrameDataPath.pathTestCaseDirRoot, "temp.json"), "w",
                  encoding="utf-8") as testCaseDataTemp:
            json.dump(test_case_data, testCaseDataTemp)
        # 遍历数据,获取已经根据不同项目或者不同模块进行划分的功能点
        for testFeature in test_case_data:
            case_tap = testFeature[0]
            case_datas = testFeature[1]
            test_case = {}
            # <editor-fold desc="根据是否参数传递创建用例执行代码">
            for caseDescript in case_datas:
                if case_data := case_datas[caseDescript][params]:
                    self.caseCountHasParams += 1
                    testcase_name = os.path.join(FrameDataPath.pathTestCaseDir,
                                                 f"test_caseHasParams{int(case_datas[caseDescript].copy()[caseCount])}.py")
                    self.__hasParamsCreate(case_tap, caseDescript, case_datas[caseDescript].copy(), testcase_name)
                else:
                    test_case[caseDescript] = (case_datas[caseDescript].copy())  # 不需要传参的剔除存放到缓存,最后集中处理
            # </editor-fold>
            # <editor-fold desc="集中处理普通用例">
            if len(test_case):
                self.caseCountCommon += 1
                testcase_name = os.path.join(FrameDataPath.pathTestCaseDir, f"test_case{self.caseCountCommon}.py")
                self.__commonCreate(case_tap, test_case, testcase_name)
            # </editor-fold>

    # 创建不需要参数传递的用例
    def __commonCreate(self, caseTap, caseData, testCaseName):
        """创建不需要参数传递的用例
        :param caseTap: 用例标签[项目名,模块名,功能点名]
        :param caseData: 用例数据
        :param testCaseName: 测试用例代码文件名,自动生成
        :return:
        """
        # <editor-fold desc="修改模板文件数据">
        base_params = {
            r'# <editor-fold desc="只是在模板中用到引用库">\nfrom lib.frameTool.achieveTestDatas import LoadTestDatas\n# </editor-fold>\n':
                "",
            r'scenes = LoadTestDatas[(][)].run[(][)][\[]0[]]\n': fr'scenes = {caseData}\n',
            r"caseTap.*?[}]'[}]\nscenes = scenes[\[]1[\]]": 'caseTap = {allureTapEpic:"%s" , allureTapFeature: "%s", allureTapStory: "%s"}' % (
                caseTap[0], caseTap[1], caseTap[2]),
            r'response = req.json[(][)]\n            ': ''
        }
        # </editor-fold>
        # <editor-fold desc="配置全局参数">
        self.__glogelParams(base_params, commonParams)
        # </editor-fold>
        testCaseTxt = self.templateCase
        for pattern in base_params.keys():
            testCaseTxt = re.sub(re.compile(pattern), base_params[pattern], testCaseTxt)
        with open(testCaseName, "w", encoding="utf-8") as w1:
            w1.write(testCaseTxt)

    # 创建需要参数传递的用例
    def __hasParamsCreate(self, caseTap, descript, caseData, testCaseName):
        """创建需要参数传递的用例
        :param caseTap: 用例标签
        :param descript: 用例描述
        :param caseData: 用例数据
        :param testCaseName: 测试用例名称
        :return:
        """
        # <editor-fold desc="修改模板文件数据">
        base_params = {
            r'# <editor-fold desc="只是在模板中用到引用库">\nfrom lib.frameTool.achieveTestDatas import LoadTestDatas\n# </editor-fold>\n': "",
            r'scenes = LoadTestDatas[(][)].run[(][)][\[]0[]]\n': r'scenes = {"%s":%s}\n' % (descript, caseData),
            r"caseTap.*?[}]'[}]\nscenes = scenes[\[]1[\]]": 'caseTap = {allureTapEpic:"%s" , allureTapFeature: "%s", allureTapStory: "%s"}' % (
                caseTap[0], caseTap[1], caseTap[2]),
            r'mark.order.*?\n': fr'mark.order({int(caseData[caseCount])})\n'
        }
        # </editor-fold>
        # <editor-fold desc="配置全局参数">
        self.__glogelParams(base_params, commonParams)
        # </editor-fold>
        # <editor-fold desc="用例之间的参数传递">
        # 设置用例之间的参数传递
        try:
            if len(dataSet := caseData[params]["set"]):
                temp_str = ""
                for key in dataSet:
                    tail = ""
                    for k in dataSet[key]:
                        # 添加一个判断,如果是数字则不需要加双引号
                        if isinstance(k, int):
                            tail = tail + '[%s]' % k
                        else:
                            tail = tail + '["%s"]' % k
                    temp_str = temp_str + r'\n            set_global_data("%s", response%s)' % (key, tail)
                base_params.update({r"response = req.json[(][)]\n": r'response = req.json()%s\n' % temp_str})
        except KeyError:
            pass
        # 获取用例之间的请求头全局参数传递
        try:
            if len(data_header := caseData[params]["header"]):
                for i in data_header:
                    temp_str = r'        reqDataHeaders.update({"%s":get_global_data("%s")})\n' % (
                        i, data_header[i])
                    # 将修改应用到模板中:请求头
                    base_params.update({
                        r'reqDataHeaders.update[(]header := reqData.get[(]reqHeader[)][)]\n':
                            fr'reqDataHeaders.update(header:= reqData.get(reqHeader))\n{temp_str}'})
        except KeyError:
            pass
        # 获取用例之间的请求体全局参数传递
        try:
            if len(data_body := caseData[params]["body"]):
                for i in data_body:
                    temp_str = r'        reqDataBody.update({"%s":get_global_data("%s")})\n' % (i, data_body[i])
                    # 将修改应用到模板中:请求体
                    base_params.update({
                        r'reqDataBody.update[(]body := reqData.get[(]reqBody[)][)]\n':
                            fr'reqDataBody.update(body := reqData.get(reqBody))\n{temp_str}'})
        except KeyError:
            pass

        # </editor-fold>
        testCaseTxt = self.templateCase
        for pattern in base_params.keys():
            testCaseTxt = re.sub(re.compile(pattern, re.S), base_params[pattern], testCaseTxt)
        with open(testCaseName, "w", encoding="utf-8") as w1:
            w1.write(testCaseTxt)

    # 封装全局参数传递方法
    def __glogelParams(self, base_params: dict, glogelParams: dict = {"header": {}, "body": {}}):
        if len(commonParam := glogelParams["header"]):  # 配置到请求头
            temp_str = ""
            for param in commonParam.keys():
                temp_str = r'        try:reqDataHeaders.update({"%s":get_global_data("%s")})\n' \
                           r'        except:pass\n' % (param, commonParam[param]) + temp_str
            # 写入到需要修改的参数集合中:请求头
            base_params.update({
                r'reqDataHeaders.update[(]header := reqData.get[(]reqHeader[)][)]\n':
                    fr'reqDataHeaders.update(header := reqData.get(reqHeader))\n{temp_str}'})
        if len(commonParam := commonParams["body"]):  # 配置到请求体
            temp_str = ""
            for param in commonParam.keys():
                temp_str = r'        try:reqDataBody.update({"%s":get_global_data("%s")})\n' \
                           r'        except:pass\n' % (param, commonParam[param]) + temp_str
            # 写入到需要修改的参数集合中:请求体
            base_params.update({
                r'reqDataBody.update[(]body := reqData.get[(]reqBody[)][)]\n': fr'reqDataBody.update(body)\n{temp_str}'
            })
        return base_params


if __name__ == '__main__':
    CreateTestCase().run()
